package com.mvc.framework.action;

import com.mvc.business.entity.GoodsForm;
import com.mvc.framework.entity.AnnotationBean;
import com.mvc.framework.entity.MethodInfo;
import com.mvc.framework.entity.ParamInfo;
import com.mvc.framework.utils.BeanUtils;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class AnnotationServlet extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		resp.setContentType("text/html;charset=utf-8");
		// TODO: 读取缓存中的配置
		List<AnnotationBean> config = (List<AnnotationBean>) this.getServletContext().getAttribute("mvcConfig");
		if (config == null) {
			resp.setStatus(500);
			return;
		}
		// /query/aaa
		String path = req.getRequestURI();
		if (path.equals("/")) {
			RequestDispatcher dis = req.getRequestDispatcher("/view/index.jsp");
			dis.forward(req, resp);
		}
		String controllerUri = "";
		String methodUri = "";
		String[] uriArr = null;
		MethodInfo methodInfo = null;
		List<String> uriList = new ArrayList<>();
		if (path != null && !"".equalsIgnoreCase(path)) {
			path = path.replace(".do", "");
			uriArr = path.startsWith("/") ? path.substring(1, path.length()).split("/") : path.split("/");
			for (String uri : uriArr) {
				uriList.add(uri);
			}
		} else {
			//todo: 抛异常：500 / 404?
			resp.setStatus(500);
			throw new ServletException("");
		}

		AnnotationBean controllerBean = null;
		for (AnnotationBean bean : config) {
			if (uriList != null && uriList.size() > 0) {
				Iterator<String> irt = uriList.iterator();
				while (irt.hasNext()) {
					String uri = irt.next();
					controllerUri = "/" + uri;
					irt.remove();
					if (controllerUri.equals(bean.getRootRequetPath())) {
						controllerBean = bean;
						break;
					}
				}
			}
		}

		if (controllerBean == null) {
			// 抛异常 404
			resp.setStatus(404);
			throw new ServletException("请求路径：" + path + " 不存在。");
		}

		if (uriList!=null &&uriList.size()>0) {
			Iterator<String> irt = uriList.iterator();
			while (irt.hasNext()) {
				String uri = irt.next();
				methodUri = "/" + uri;
				if (controllerBean.getMethodInfoMap() != null && controllerBean.getMethodInfoMap().get(methodUri) != null) {
					methodInfo = controllerBean.getMethodInfoMap().get(methodUri);
					break;
				}
			}
		}

		if (methodInfo == null) {
			resp.setStatus(404);
			throw new ServletException("请求路径：" + path + " 不存在。");
		}
		req.getParameterMap();
		try {
			Class claz =Class.forName(controllerBean.getClazName());
			Method method = null;
			Object[] args = null;
			if (methodInfo.getParamInfoList() != null && !methodInfo.getParamInfoList().isEmpty()) {
				Set<ParamInfo> paramInfoList = methodInfo.getParamInfoList();
				Class[] methodParams = new Class[paramInfoList.size()];
				args = new Object[paramInfoList.size()];
//				args = new ArrayList<>();

				Iterator<ParamInfo> paramIrt = paramInfoList.iterator();
				int i = 0;
				while (paramIrt.hasNext()) {
					ParamInfo paramInfo = paramIrt.next();
					if (BeanUtils.isBasicDataType(paramInfo.getType())) {
						methodParams[i] = BeanUtils.basicDataType2Class(paramInfo.getType());
					} else {
						methodParams[i] = Class.forName(paramInfo.getType());
					}

					// build invoke args
					if (paramInfo.getType().equalsIgnoreCase("javax.servlet.http.HttpServletRequest")) {
						args[i] = req;

					} else if(paramInfo.getType().equalsIgnoreCase("javax.servlet.http.HttpServletResponse")) {
						args[i] = resp;

					} else if(paramInfo.getType().startsWith("java.lang")) {
						String arg = req.getParameter(paramInfo.getName());
						Class a = Class.forName(paramInfo.getType());
						//args[i] = arg == null ? (Object) a.newInstance() : (Object) arg;
						args[i] = arg == null ? (Object)0d : (Object) arg;

					} else if(BeanUtils.isBasicDataType(paramInfo.getType())) {
						if (paramInfo.getType().equalsIgnoreCase("boolean")) {
							boolean arg = Boolean.valueOf(req.getParameter(methodInfo.getName())).booleanValue();
							args[i] = (Object) arg;
						} else {
							String arg = req.getParameter(paramInfo.getName());
							if (arg == null) {
								if(paramInfo.getType().equalsIgnoreCase("int")) {
									args[i] = (Object) 0;
								}
								Class result = BeanUtils.basicDataType2Class(paramInfo.getType());
								args[i] = result;
							} else {
								args[i] = (Object) arg;
							}
						}

					} else {
						Class c = Class.forName(paramInfo.getType());
						//args.add(BeanUtils.fillClazFromRequest(c, req));
						args[i] = BeanUtils.fillClazFromRequest(c, req);
					}
					i ++;
				}
				method = claz.getMethod(methodInfo.getName(), methodParams);
			} else {
				method = claz.getMethod(methodInfo.getName());
			}
			if (args == null) {
				//args = new ArrayList<>();
				args = new Object[0];
			}
			// 基本类型与其包装类的数据格式要怎么处理？
			Object result = method.invoke(claz.newInstance(), req, GoodsForm.class.newInstance(), null, 2);
			if (result instanceof String) {
				RequestDispatcher dis = req.getRequestDispatcher(result.toString());
				dis.forward(req, resp);
			}//else 其他情况暂不处理
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		}
		// TODO: 反射执行方法
	}

	public static void main(String[] args) {
		String aa = "/query/aaa";
		System.out.println(aa.substring("/query".length()));
		String[] strArr = aa.split("/");
		for (String s : strArr) {
			System.out.println(s);
		}
	}
}
